#include <stdio.h>
#include <time.h>
#include <math.h>
#include <sys/time.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
#include <sched.h>
#include <stdarg.h>

#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/resource.h>

#include "os.h"
#include "sm_trace.h"

#include "android/log.h"

#define LOG_TAG "DVB-CI"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO  , LOG_TAG, __VA_ARGS__)


unsigned int SM_OsThreadCreateEx (unsigned int u32StackSize,
							  unsigned int  (*fStartAddress) (void *), 									            
							  void *ArgList, 
							  unsigned int * phThreadId, unsigned int u32Proity)
{
	pthread_t dwThread;
	pthread_attr_t* pAttr = NULL; 
	pthread_attr_t		attr;
	unsigned int u32ProiMax, u32ProiMin;
	struct sched_param param;
	int ret;
	
	if (0 != pthread_attr_init(&attr))
	{
		return 0;
	}

	if(u32StackSize < 100*1024)
		u32StackSize = 100*1024;
		
	// Set the stack size of the thread
	if (0 != pthread_attr_setstacksize(&attr, (size_t)u32StackSize))
	{
		SM_TRACE_NOTIFY(TRMOD_KAPI,"SM_OsThreadCreate() - create thread failed!\r\n");
		return 0;
	}

	u32ProiMax = sched_get_priority_max(SCHED_RR);
	u32ProiMin = sched_get_priority_min(SCHED_RR);
	SM_TRACE_NOTIFY(TRMOD_KAPI,"SM_OsThreadCreate() - create thread u32ProiMax = %d, u32ProiMin = %d\r\n", u32ProiMax, u32ProiMin);
	LOGI("SM_OsThreadCreate() - create thread u32ProiMax = %d, u32ProiMin = %d\r\n", u32ProiMax, u32ProiMin);
	if(u32ProiMax > u32ProiMin)
	{
		pthread_attr_setschedpolicy(&attr, SCHED_RR);
		param.sched_priority = u32Proity*(u32ProiMax-u32ProiMin)/100;
		SM_TRACE_NOTIFY(TRMOD_KAPI,"SM_OsThreadCreate() - create thread param.sched_priority = %d\r\n", param.sched_priority);
		LOGI("SM_OsThreadCreate() - create thread param.sched_priority = %d\r\n", param.sched_priority);
		ret = pthread_attr_setschedparam(&attr, &param);
		LOGI("SM_OsThreadCreate() - create thread pthread_attr_setschedparam ret = %d\r\n", ret);
		//pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
	}

	pAttr = &attr;
	pthread_create(&dwThread, pAttr, (void *)fStartAddress, ArgList);
	*phThreadId = (unsigned int)dwThread;
	if(pAttr)
		pthread_attr_destroy(pAttr);
		
	return (unsigned int)dwThread;
}

int SM_OsSetPriority(unsigned int u32Priority)
{
	int s32Prio;
	int ret;
	
	s32Prio = getpriority(PRIO_PROCESS, 0);
	LOGI("SM_OsSetPriority() - get s32Prio = %d\r\n", s32Prio);
	u32Priority = u32Priority*38/100;
	s32Prio = 19 - (int)u32Priority;
	LOGI("SM_OsSetPriority() - set s32Prio = %d\r\n", s32Prio);
	ret = setpriority(PRIO_PROCESS, 0, s32Prio);
	if(ret == 0)
		LOGI("SM_OsSetPriority() - ret = %d\r\n", ret);
	else
		LOGI("SM_OsSetPriority() - success\r\n");
	return 0;
}


unsigned int SM_OsThreadCreate (unsigned int u32StackSize,
							  unsigned int  (*fStartAddress) (void *), 									            
							  void *ArgList, 
							  unsigned int * phThreadId)
{
	pthread_t dwThread;
	pthread_attr_t* pAttr = NULL; 
	pthread_attr_t		attr;

	if (0 != pthread_attr_init(&attr))
	{
		return 0;
	}
	pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
	
	if (0 != u32StackSize)
	{
		if(u32StackSize < 100*1024)
			u32StackSize = 100*1024;
			
		// Set the stack size of the thread
		if (0 != pthread_attr_setstacksize(&attr, (size_t)u32StackSize))
		{
			SM_TRACE_NOTIFY(TRMOD_KAPI,"SM_OsThreadCreate() - create thread failed!\r\n");
			return 0;
		}
	}
	pAttr = &attr;
	pthread_create(&dwThread, pAttr, (void *)fStartAddress, ArgList);
	*phThreadId = (unsigned int)dwThread;
	if(pAttr)
		pthread_attr_destroy(pAttr);
		
	return (unsigned int)dwThread;
}

void SM_OsThreadDestroy (unsigned int hThreadId)
{

}

unsigned int SM_OsThreadGetCurId(void)
{
	return (unsigned int)pthread_self();
}

void SM_OsThreadSleep(unsigned int u32SleepMs)
{
	static int 			s_isSemInited = 0;
	static unsigned int 	s_semTmout;

	if (!s_isSemInited)
	{
		SM_TRACE_NOTIFY(TRMOD_KAPI,"SM_OsThreadSleep() - init semaphore\r\n");
		SM_OsSemCreate(&s_semTmout, "sm_sleep_tmout", 0);
		s_isSemInited = 1;
	}

	SM_OsSemWait(&s_semTmout, u32SleepMs);
}

void SM_OsSemCreate (unsigned int *pSemaphore, unsigned char *p8Name,
					unsigned int u32InitialCount)
{
	unsigned long	rc;

	SM_TRACE_ENTRY(TRMOD_KAPI,"SM_OsSemCreate() - entry, "
			"pSemaphore=0x%08X,name=%s,initial_count=%d\r\n",
			pSemaphore, p8Name, u32InitialCount);

	rc = sem_init((sem_t *)pSemaphore, 0, u32InitialCount);

	SM_TRACE_RETURN(TRMOD_KAPI,"SM_OsSemCreate() - return, "
				"pSemaphore=0x%08X,rc=%d\r\n", pSemaphore,rc);
}

void SM_OsSemDestroy (unsigned int *pSemaphore)
{
	sem_destroy((sem_t*)pSemaphore);
}

int SM_OsSemWait (unsigned int *pSemaphore, unsigned int u32TimeoutMs)
{
	unsigned long 	rc;
	unsigned long	tmpMsec,tmpUsec;
	struct timespec	tsTimeOut;
	struct timeval 	now;

	SM_TRACE_ENTRY(TRMOD_KAPI,"SM_OsSemWait() - entry, "
			"pSemaphore=0x%08X,u32TimeoutMs=%dms\r\n", pSemaphore, u32TimeoutMs);

	memset(&tsTimeOut, 0x00, sizeof(tsTimeOut));
	gettimeofday (&now, NULL);

    //����ķ���
	//tsTimeOut.tv_sec = now.tv_sec + timeout_ms/1000;
    //tsTimeOut.tv_nsec = (now.tv_usec + (timeout_ms % 1000) * 1000 ) * 1000;

	now.tv_sec = now.tv_sec + u32TimeoutMs/1000;
	tmpMsec = u32TimeoutMs % 1000;
	tmpUsec = now.tv_usec + tmpMsec * 1000;
	if (tmpUsec >= 1000000)
	{
		now.tv_sec += 1;
		now.tv_usec = tmpUsec % 1000000;
	}
	else
		now.tv_usec = tmpUsec;

	tsTimeOut.tv_sec = now.tv_sec;
	tsTimeOut.tv_nsec = now.tv_usec * 1000;

	rc = (u32TimeoutMs == (unsigned long)-1
			? sem_wait((sem_t *)pSemaphore): sem_timedwait((sem_t *)pSemaphore, &tsTimeOut));

	SM_TRACE_RETURN(TRMOD_KAPI,"SM_OsSemWait() - return, pSemaphore=0x%08X, semrc=%d,rc=%s\r\n",
				pSemaphore, rc, rc == 0 ? "TRUE" : "FALSE"); //ETIMEDOUT

	return rc == 0 ? 1 : 0;
}

void SM_OsSemRelease (unsigned int *pSemaphore)
{
	SM_TRACE_ENTRY(TRMOD_KAPI,"SM_OsSemWait() - entry, "
					"pSemaphore0x%08X\r\n", pSemaphore);

	sem_post((sem_t *)pSemaphore );

	SM_TRACE_ENTRY(TRMOD_KAPI,"SM_OsSemWait - return, "
					"pSemaphore=0x%08X\r\n", pSemaphore);
}

unsigned int SM_OsMsecCountGet (void)
{
	//unit: ms
	unsigned long tick;
	static struct timeval stStartTimeValue = {0, 0};
	struct timeval    stTimeValue;  	
	struct timezone tz;  

	if(stStartTimeValue.tv_sec == 0)
	{
		gettimeofday(&stStartTimeValue, &tz);
		tick = 0;
	}
	else
	{
		gettimeofday(&stTimeValue, &tz);
		tick = (stTimeValue.tv_usec - stStartTimeValue.tv_usec)/1000;
		tick += (stTimeValue.tv_sec - stStartTimeValue.tv_sec)*1000;
	}
	
	return tick;
}

unsigned int SM_OsTickCountGet (void)
{
	return (unsigned long)time(NULL);
}

int SM_OsWallTimeGet(SM_TIME_T* pstTime)
{
	time_t timep; 
	struct tm *p; 

	if(pstTime)
	{
		time(&timep); 
		p = localtime(&timep);
		pstTime->m_u32Year = 1900+p->tm_year;
		pstTime->m_u32Mon = 1 + p->tm_mon;
		pstTime->m_u32Yday = p->tm_mday;
		pstTime->m_u32Wday = p->tm_wday;
		pstTime->m_u32Hour = p->tm_hour;
		pstTime->m_u32Min = p->tm_min;
		pstTime->m_u32Sec = p->tm_sec;
	}
	return 0;
}

/****************************************************************************
*
* Memory functions
*
****************************************************************************/
void* SM_OsMemAllocate(unsigned int u32Size)
{
	return malloc(u32Size);
}

void SM_OsMemFree(void* memblock)
{
	free(memblock);
}

//������û��ʹ��
void* SM_OsMemRealloc(void *memblock, unsigned int u32Size)
{
	realloc(memblock, u32Size);
}

/************************************************************************/
/* DEBUG                                                                */
/************************************************************************/

static pfDebugOutput pfDebug = NULL;

void SM_RegistorDebugFun(pfDebugOutput pfDebugFun)
{
	pfDebug = pfDebugFun;
}

void SM_Printf_Error(const char *fmt, ... )
{
	char			szBuffer[4096];
	va_list			va;
	int len;

	va_start(va, fmt);

	// limit the written size and reserve one byte for NULL character
	len = vsnprintf(szBuffer, sizeof(szBuffer) - 1, fmt, va);
	va_end(va);

	if (-1 == len)
	{
		// the string is truncated because of lacking memory
		len = sizeof(szBuffer) -1;
	}
	szBuffer[len] = '\0';
	if(pfDebug)
		pfDebug(SM_DEBUG_ERROR, szBuffer);
}

void SM_Printf(const char *fmt, ... )
{
	char			szBuffer[4096];
	va_list			va;
	int len;

	va_start(va, fmt);

	// limit the written size and reserve one byte for NULL character
	len = vsnprintf(szBuffer, sizeof(szBuffer) - 1, fmt, va);
	va_end(va);

	if (-1 == len)
	{
		// the string is truncated because of lacking memory
		len = sizeof(szBuffer) -1;
	}
	szBuffer[len] = '\0';
	if(pfDebug)
		pfDebug(SM_DEBUG_COMMON, szBuffer);
}

/************************************************************************/
/* socket                                                                */
/************************************************************************/
int SM_SockSOcket(int s32Domain, int s32Type, int s32Protocol)
{
	int domain = -1;
	int type = -1;
	int protocol = -1;
	int s = 0;

	switch(s32Domain)
	{
	case SM_SOCKDOMAIN_AFINET:
		domain = AF_INET;
		break;
	case SM_SOCKDOMAIN_AFINET6:
		domain = AF_INET6;
		break;
	default:
		break;
	}

	switch(s32Type)
	{
	case SM_SOCKTYPE_STREAM:
		type = SOCK_STREAM;
		break;
	case SM_SOCKTYPE_DGRAM:
		type = SOCK_DGRAM;
		break;
	case SM_SOCKTYPE_RAW:
		type = SOCK_RAW;
		break;
	default:
		break;
	}

	switch(s32Protocol)
	{
	case SM_SOCKPROTO_AUTO:
		protocol = 0;
		break;
	case SM_SOCKPROTO_TCP:
		protocol = IPPROTO_TCP;
		break;
	case SM_SOCKPROTO_UDP:
		protocol = IPPROTO_UDP;
		break;
	default:
		break;
	}

	if(domain!=-1 && type!=-1 && protocol!=-1)
		s = socket(domain, type, protocol);

	if(s == -1)
		SM_Printf_Error("SM_SockSOcket() - return error: %s\r\n", strerror(errno));

	
	return (int)s;
}

int SM_SockBind(int s32Sockfd, const struct SM_SOCKADDR* psAddr, SM_SOCKLEN_T u32AddrLen)
{
	int s = s32Sockfd;
	int rc = 0;
	struct sockaddr addr;

	if(s==0 || psAddr==NULL)
		return -1;

	addr = *(struct sockaddr*)psAddr;
	switch(addr.sa_family)
	{
	case SM_SOCKDOMAIN_AFINET:
		addr.sa_family = AF_INET;
		break;
	case SM_SOCKDOMAIN_AFINET6:
		addr.sa_family = AF_INET6;
		break;
	default:
		rc = SM_SOCK_ERROR;
		break;
	}

	if(rc != SM_SOCK_ERROR)
		rc = bind(s, (struct sockaddr*)&addr, sizeof(addr));

	if(rc == -1)
		SM_Printf_Error("SM_SockBind() - return error: %s\r\n", strerror(errno));

	return rc;
}

int SM_SockListen(int s32Sockfd, unsigned int u32Backlog)
{
	int rc = 0;
	int s = s32Sockfd;
	int backlog = (int)u32Backlog;

	if(s==0)
		return -1;

	rc = listen(s, (int)backlog);

	if(rc == -1)
		SM_Printf_Error("SM_SockBind() - return error: %s\r\n", strerror(errno));

	return rc;
}

int SM_SockConnect(int s32Sockfd, const struct SM_SOCKADDR* psAddr, SM_SOCKLEN_T u32AddrLen)
{
	int rc = 0;
	int s = s32Sockfd;
	struct sockaddr addr;

	if(s==0 || psAddr==NULL)
		return SM_SOCK_ERROR;

	addr = *(struct sockaddr*)psAddr;
	switch(addr.sa_family)
	{
	case SM_SOCKDOMAIN_AFINET:
		addr.sa_family = AF_INET;
		break;
	case SM_SOCKDOMAIN_AFINET6:
		addr.sa_family = AF_INET6;
		break;
	default:
		rc = SM_SOCK_ERROR;
		break;
	}

	if(rc != SM_SOCK_ERROR)
		rc = connect(s, (struct sockaddr*)&addr, sizeof(struct sockaddr));

	if(rc == -1)
		SM_Printf_Error("SM_SockBind() - return error: %s\r\n", strerror(errno));

	return rc;
}

int SM_SockAccept(int s32Sockfd, struct SM_SOCKADDR* psAddr, SM_SOCKLEN_T* pu32AddrLen)
{
	int s = s32Sockfd;
	int news;

	if(s==0 || psAddr==NULL)
		return SM_SOCK_ERROR;

	news = accept(s, (struct sockaddr*)psAddr, (int*)pu32AddrLen);
	if(news != SM_SOCK_ERROR)
	{
		switch(psAddr->sin_family)
		{
		case AF_INET:
			psAddr->sin_family = SM_SOCKDOMAIN_AFINET;
			break;
		case AF_INET6:
			psAddr->sin_family = SM_SOCKDOMAIN_AFINET6;
			break;
		default:
			news = 0;
			break;
		}
	}

	return news;
}

unsigned int SM_SockSend(int s32Sockfd, const void *buf, unsigned int len, int flags)
{
	int rc = 0;
	int s = s32Sockfd;
	int s32Len = (int)len;

	if(s==0 || buf==NULL)
		return 0;

	rc = send(s, buf, s32Len, flags);
	if(rc <= 0)
		SM_Printf_Error("SM_SockSend() - return error: %s\r\n", strerror(errno));

	return rc;
}

unsigned int SM_SockRecv(int s32Sockfd, void *buf, unsigned int len, int flags)
{
	unsigned int rc = 0;
	int s = (int)s32Sockfd;
	int s32Len = (int)len;

	if(s==0 || buf==NULL)
		return 0;

	rc = recv(s, buf, s32Len, flags);
	if(rc <= 0)
		SM_Printf_Error("SM_SockRecv() - return error: %s\r\n", strerror(errno));

	return rc;
}

unsigned int SM_SockSendTo(int s32Sockfd, const void *buf, size_t len, int flags, const struct SM_SOCKADDR *dest_addr, SM_SOCKLEN_T addrlen)
{
	int rc = 0;
	int s = (int)s32Sockfd;
	int s32Len = (int)len;
	unsigned int u32SendSized = 0;
	struct sockaddr addr;

	if(s==0 || buf==NULL || dest_addr==NULL)
		return 0;

	addr = *(struct sockaddr*)dest_addr;
	switch(addr.sa_family)
	{
	case SM_SOCKDOMAIN_AFINET:
		addr.sa_family = AF_INET;
		break;
	case SM_SOCKDOMAIN_AFINET6:
		addr.sa_family = AF_INET6;
		break;
	default:
		rc = SM_SOCK_ERROR;
		break;
	}


	if(rc != SM_SOCK_ERROR)
	{
		u32SendSized = (unsigned int)sendto(s, buf, s32Len, flags, (struct sockaddr*)&addr, (int)addrlen);
	}

	return u32SendSized;
}

unsigned int SM_SockRecvFrom(int s32Sockfd, void *buf, size_t len, int flags, struct SM_SOCKADDR *src_addr, SM_SOCKLEN_T *addrlen)
{
	int rc = 0;
	int s = (int)s32Sockfd;
	int s32Len = (int)len;
	unsigned int u32RecvSized = 0;

	if(s==0 || buf==NULL || src_addr==NULL)
		return 0;

	switch(src_addr->sin_family)
	{
	case SM_SOCKDOMAIN_AFINET:
		src_addr->sin_family = AF_INET;
		break;
	case SM_SOCKDOMAIN_AFINET6:
		src_addr->sin_family = AF_INET6;
		break;
	default:
		rc = SM_SOCK_ERROR;
		break;
	}

	if(rc != SM_SOCK_ERROR)
	{
		u32RecvSized = (unsigned int)recvfrom(s, buf, s32Len, flags, (struct sockaddr*)src_addr, (int*)addrlen);
		switch(src_addr->sin_family)
		{
		case AF_INET:
			src_addr->sin_family = SM_SOCKDOMAIN_AFINET;
			break;
		case AF_INET6:
			src_addr->sin_family = SM_SOCKDOMAIN_AFINET6;
			break;
		default:
			rc = SM_SOCK_ERROR;
			break;
		}
	}

	return u32RecvSized;
}

int SM_SockClose(int s32Sockfd)
{
	int rc = 0;

	if(s32Sockfd==0)
		return SM_SOCK_ERROR;

	rc = close(s32Sockfd);

	return rc;
}

int SM_SockShutdown(int s, int how)
{
	return shutdown(s, how);
}

int SM_SockSetSockOpt(int s32Sockfd, int level, int optname, const void* optval, unsigned int optlen)
{
	int actualLevel;
	int actualOptname;
	int s = s32Sockfd;

	switch(level)
	{
	case SM_SOL_SOCKET:
		actualLevel = SOL_SOCKET;
		break;
	case SM_IPPROTO_IP:
		actualLevel = IPPROTO_IP;
		break;
	case SM_IPPROTO_IPV6:
		actualLevel = IPPROTO_IPV6;
		break;
	case SM_IPPROTO_TCP:
		actualLevel = IPPROTO_TCP;
		break;
	default:
		return SM_SOCK_ERROR;
	}

	if(actualLevel == SOL_SOCKET)
	{
		switch(optname)
		{
		case SM_SO_BROADCAST:
			actualOptname = SO_BROADCAST;
			break;
		case SM_SO_DEBUG:
			actualOptname = SO_DEBUG;
			break;
		case SM_SO_DONTROUTE:
			actualOptname = SO_DONTROUTE;
			break;
		case SM_SO_ERROR:
			actualOptname = SO_ERROR;
			break;
		case SM_SO_KEEPALIVE:
			actualOptname = SO_KEEPALIVE;
			break;
//		case SM_SO_DONTLINGER:
//			actualOptname = SO_DONTLINGER;
//			break;
		case SM_SO_LINGER:
			actualOptname = SO_LINGER;
			break;
		case SM_SO_OOBINLINE:
			actualOptname = SO_OOBINLINE;
			break;
		case SM_SO_RCVBUF:
			actualOptname = SO_RCVBUF;
			break;
		//case SM_SO_MAX_MSG_SIZE:
		//	actualOptname = SO_MAX_MSG_SIZE;
		//	break;
		case SM_SO_SNDBUF:
			actualOptname = SO_SNDBUF;
			break;
		case SM_SO_RCVLOWAT:
			actualOptname = SO_RCVLOWAT;
			break;
		case SM_SO_SNDLOWAT:
			actualOptname = SO_SNDLOWAT;
			break;
		case SM_SO_RCVTIMEO:
			actualOptname = SO_RCVTIMEO;
			break;
		case SM_SO_SNDTIMEO:
			actualOptname = SO_SNDTIMEO;
			break;
		case SM_SO_REUSEADDR:
			actualOptname = SO_REUSEADDR;
			break;
		//case SM_SO_EXCLUSIVEADDRUSE:
		//	actualOptname = SO_EXCLUSIVEADDRUSE;
		//	break;
		case SM_SO_TYPE:
			actualOptname = SO_TYPE;
			break;
		//case SM_SO_BSDCOMPAT:
		//	optname = SO_BSP_STATE
		//	break;
		default:
			return SM_SOCK_ERROR;
		}
	}
	else if(actualLevel == IPPROTO_IP)
	{
		
	}
	else if(actualLevel == IPPROTO_IPV6)
	{
		
	}
	else if(actualLevel == IPPROTO_TCP)
	{
		
	}
	return setsockopt(s, actualLevel, actualOptname, optval, optlen);
}

int SM_SockGetSockOpt(int s32Sockfd, int level, int optname, void* optval, unsigned int* optlen)
{
	int actualLevel;
	int actualOptname;
	int s = s32Sockfd;

	switch(level)
	{
	case SM_SOL_SOCKET:
		actualLevel = SOL_SOCKET;
		break;
	case SM_IPPROTO_IP:
		actualLevel = IPPROTO_IP;
		break;
	case SM_IPPROTO_IPV6:
		actualLevel = IPPROTO_IPV6;
		break;
	case SM_IPPROTO_TCP:
		actualLevel = IPPROTO_TCP;
		break;
	default:
		return SM_SOCK_ERROR;
	}

	if(actualLevel == SM_SOL_SOCKET)
	{
		switch(optname)
		{
		case SM_SO_BROADCAST:
			actualOptname = SO_BROADCAST;
			break;
		case SM_SO_DEBUG:
			actualOptname = SO_DEBUG;
			break;
		case SM_SO_DONTROUTE:
			actualOptname = SO_DONTROUTE;
			break;
		case SM_SO_ERROR:
			actualOptname = SO_ERROR;
			break;
		case SM_SO_KEEPALIVE:
			actualOptname = SO_KEEPALIVE;
			break;
//		case SM_SO_DONTLINGER:
//			actualOptname = SO_DONTLINGER;
//			break;
//		case SM_SO_LINGER:
//			actualOptname = SO_LINGER;
//			break;
		case SM_SO_OOBINLINE:
			actualOptname = SO_OOBINLINE;
			break;
		case SM_SO_RCVBUF:
			actualOptname = SO_RCVBUF;
			break;
		//case SM_SO_MAX_MSG_SIZE:
		//	actualOptname = SO_MAX_MSG_SIZE;
		//	break;
		case SM_SO_SNDBUF:
			actualOptname = SO_SNDBUF;
			break;
		case SM_SO_RCVLOWAT:
			actualOptname = SO_RCVLOWAT;
			break;
		case SM_SO_SNDLOWAT:
			actualOptname = SO_SNDLOWAT;
			break;
		case SM_SO_RCVTIMEO:
			actualOptname = SO_RCVTIMEO;
			break;
		case SM_SO_SNDTIMEO:
			actualOptname = SO_SNDTIMEO;
			break;
		case SM_SO_REUSEADDR:
			actualOptname = SO_REUSEADDR;
			break;
		//case SM_SO_EXCLUSIVEADDRUSE:
		//	actualOptname = SO_EXCLUSIVEADDRUSE;
		//	break;
		case SM_SO_TYPE:
			actualOptname = SO_TYPE;
			break;
			//case SM_SO_BSDCOMPAT:
			//	optname = SO_BSP_STATE
			//	break;
		default:
			return SM_SOCK_ERROR;
		}
	}
	else if(actualLevel == IPPROTO_IP)
	{

	}
	else if(actualLevel == IPPROTO_IPV6)
	{

	}
	else if(actualLevel == IPPROTO_TCP)
	{

	}
	return getsockopt(s, actualLevel, actualOptname, optval, optlen);
}

int SM_SockIoctlsocket(int s32Sockfd, int cmd, unsigned int* argp)
{
	long actualCmd;
	int s = s32Sockfd;
	int flag;

	flag = fcntl(s, F_GETFL, 0);
	
	switch(cmd)
	{
	case SM_FIONBIO:
		if(*argp == 1)
			flag |= O_NONBLOCK;
		else
			flag &= ~O_NONBLOCK;
		break;
//	case SM_FIONREAD:
//		actualCmd = FIONREAD;
//		break;
	case SM_SIOCATMARK:
		actualCmd = SIOCATMARK;
		break;
	default:
		return SM_SOCK_ERROR;
	}
	//return ioctlsocket(s, actualCmd, argp);
	return fcntl(s, F_SETFL, flag);
}

struct SM_HOSTENT* SM_SockGetHostByName(const char* name)
{
	return (struct SM_HOSTENT*)gethostbyname(name);
}

int SM_SockStartup()
{
	return 0;
}

int SM_SockStop()
{
	return 0;
}

static void SM_SockTranslate(SM_FD_SET_T* fromSet, fd_set* toSet)
{
	unsigned int i;
	int fd;
	
	FD_ZERO(toSet);
	if(fromSet)
	{
		for(i=0; i<fromSet->fd_count; i++)
		{
			fd = fromSet->fd_array[i];
			FD_SET(fd, toSet);
		}
	}
}

int SM_SockFDIsSet(int fd, SM_FD_SET_T*set)
{
	int rc = -1;
	unsigned int i;

	for(i=0; i<set->fd_count; i++)
	{
		if(set->fd_array[i] == fd)
		{
			break;
		}
	}

	if(i < set->fd_count)
		rc = 0;
	else
		rc = 1;
	
	return rc;
}

int SM_SockSelect(int nfds, SM_FD_SET_T* readfds, SM_FD_SET_T* writefds, SM_FD_SET_T* exceptfds, const struct SM_Timeval* timeout)
{
	int rc;
	struct timeval to;
	fd_set toReadSet;
	fd_set toWriteSet;
	fd_set toExceptSet;
	unsigned int i;

	to.tv_sec = timeout->tv_sec;
	to.tv_usec = timeout->tv_usec;
	
	SM_SockTranslate(readfds, &toReadSet);
	SM_SockTranslate(writefds, &toWriteSet);
	SM_SockTranslate(exceptfds, &toExceptSet);
	rc = select(nfds, readfds? &toReadSet:NULL, writefds? &toWriteSet:NULL, exceptfds? &toExceptSet:NULL, &to);

	if(readfds)
	{
		for(i=0; i<readfds->fd_count; i++)
		{
			if(FD_ISSET(readfds->fd_array[i], &toReadSet))
				readfds->fd_array[i] = 0;
		}
	}

	if(writefds)
	{
		for(i=0; i<writefds->fd_count; i++)
		{
			if(FD_ISSET(writefds->fd_array[i], &toWriteSet))
				writefds->fd_array[i] = 0;
		}
	}

	if(exceptfds)
	{
		for(i=0; i<exceptfds->fd_count; i++)
		{
			if(FD_ISSET(exceptfds->fd_array[i], &toExceptSet))
				exceptfds->fd_array[i] = 0;
		}
	}


	return rc;
}

unsigned short SM_SockHtons(unsigned short hostshort)
{
	return htons(hostshort);
}

unsigned short SM_SockNtohs(unsigned short netshort)
{
	return ntohs(netshort);
}

unsigned long SM_SockHtonl(unsigned long hostlong)
{
	return htonl(hostlong);
}

unsigned long SM_SockNtohl(unsigned long netlong)
{
	return ntohl(netlong);
}
char* SM_SockInetNtoa(struct SM_IN_ADDR inAddr)
{
	static char szName[17];

	sprintf(szName, "%d.%d.%d.%d", ((char*)(&inAddr.net_addr))[0], ((char*)(&inAddr.net_addr))[1], ((char*)(&inAddr.net_addr))[2], ((char*)(&inAddr.net_addr))[3]);

	return szName;
}

int SM_SockInoreSigPipe()
{
	if(signal(SIGPIPE,SIG_IGN) == SIG_ERR)
		return -1;
	return 0;
}
